#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
北交所数据同步程序
主程序入口，负责整合各个模块实现完整的数据同步流程
"""

import os
import sys
import logging
import argparse
import yaml
from datetime import datetime, timedelta
from typing import Optional, List, Dict, Any
import traceback

# 导入自定义模块
from database import DatabaseManager, DataSyncDAO
from api_client import APIClient, ProjectDataFetcher, APIException, OperationalAPIClient, ProjectIdFetcher
from data_processor import DataProcessor

class DataSyncManager:
    """
    数据同步管理器
    负责协调各个模块完成数据同步任务
    """
    
    def __init__(self, config_path: str = 'config.yaml'):
        """
        初始化数据同步管理器
        
        Args:
            config_path: 配置文件路径
        """
        self.config_path = config_path
        self.config = self._load_config()
        self.logger = self._setup_logging()
        
        # 初始化各个组件
        self.db_manager = None
        self.api_client = None
        self.data_processor = None
        self.data_fetcher = None
        self.data_sync_dao = None
        self.operational_api_client = None
        self.project_id_fetcher = None
        
        self._init_components()
    
    def _load_config(self) -> Dict[str, Any]:
        """
        加载配置文件
        
        Returns:
            配置字典
        """
        try:
            with open(self.config_path, 'r', encoding='utf-8') as f:
                config = yaml.safe_load(f)
            return config
        except Exception as e:
            print(f"加载配置文件失败: {e}")
            sys.exit(1)
    
    def _setup_logging(self) -> logging.Logger:
        """
        设置日志配置
        
        Returns:
            日志记录器
        """
        log_config = self.config.get('logging', {})
        
        # 创建logs目录
        log_file = log_config.get('file', 'logs/sync.log')
        log_dir = os.path.dirname(log_file)
        if log_dir and not os.path.exists(log_dir):
            os.makedirs(log_dir)
        
        # 配置日志格式
        log_format = log_config.get('format', '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        log_level = getattr(logging, log_config.get('level', 'INFO').upper())
        
        # 配置根日志记录器
        logging.basicConfig(
            level=log_level,
            format=log_format,
            handlers=[
                logging.FileHandler(log_file, encoding='utf-8'),
                logging.StreamHandler(sys.stdout)
            ]
        )
        
        logger = logging.getLogger(__name__)
        logger.info("日志系统初始化完成")
        return logger
    
    def _init_components(self):
        """
        初始化各个组件
        """
        try:
            self.logger.info("开始初始化组件...")
            
            # 初始化数据库管理器
            self.db_manager = DatabaseManager(self.config_path)
            self.data_sync_dao = DataSyncDAO(self.db_manager)
            
            # 初始化API客户端
            self.api_client = APIClient(self.config_path)
            self.data_fetcher = ProjectDataFetcher(self.api_client)
            
            # 初始化数据处理器
            self.data_processor = DataProcessor(self.config_path)
            
            # 初始化房源运营信息API客户端
            self.operational_api_client = OperationalAPIClient(self.config_path)
            
            # 初始化项目ID获取器
            self.project_id_fetcher = ProjectIdFetcher(self.db_manager)
            
            self.logger.info("组件初始化完成")
            
        except Exception as e:
            self.logger.error(f"组件初始化失败: {e}")
            raise
    
    def test_connections(self) -> bool:
        """
        测试各个连接
        
        Returns:
            测试是否成功
        """
        try:
            self.logger.info("开始测试连接...")
            
            # 测试API连接
            if not self.api_client.test_connection():
                self.logger.error("项目数据API连接测试失败")
                return False
            
            # 测试房源运营信息API连接
            if not self.operational_api_client.test_connection():
                self.logger.error("房源运营信息API连接测试失败")
                return False
            
            # 测试数据库连接
            try:
                test_result = self.db_manager.execute_query("SELECT 1 as test")
                if not test_result or test_result[0]['test'] != 1:
                    self.logger.error("数据库连接测试失败")
                    return False
            except Exception as e:
                self.logger.error(f"数据库连接测试失败: {e}")
                return False
            
            self.logger.info("连接测试通过")
            return True
            
        except Exception as e:
            self.logger.error(f"连接测试失败: {e}")
            return False
    
    def sync_operational_data(self) -> Dict[str, Any]:
        """
        同步房源运营信息数据
        
        Returns:
            同步结果统计
        """
        try:
            self.logger.info("开始同步房源运营信息数据")
            
            # 需要检索projectId的表
            table_names = [
                'bjht_real_estate_transfer',
                'bjhl_bulk', 
                'bjhl_info_disclosure',
                'bjht_house_rent',
                'bjhl_house_rent'
            ]
            
            # 获取所有projectId
            project_ids = self.project_id_fetcher.get_project_ids_from_tables(table_names)
            
            if not project_ids:
                self.logger.info("未找到任何projectId，跳过房源运营信息同步")
                return {
                    'success': True,
                    'total_projects': 0,
                    'fetched_count': 0,
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            self.logger.info(f"共获取到 {len(project_ids)} 个projectId")
            
            # 批量获取房源运营信息（为了避免请求过大，可以分批处理）
            batch_size = 100  # 每批100个项目ID
            all_operational_data = []
            
            for i in range(0, len(project_ids), batch_size):
                batch_project_ids = project_ids[i:i + batch_size]
                self.logger.info(f"处理第 {i//batch_size + 1} 批，项目数: {len(batch_project_ids)}")
                
                try:
                    # 获取房源运营信息
                    response = self.operational_api_client.get_operational_data(batch_project_ids)
                    data = response.get('data', [])
                    all_operational_data.extend(data)
                    
                    self.logger.info(f"第 {i//batch_size + 1} 批获取到 {len(data)} 条数据")
                    
                except Exception as e:
                    self.logger.error(f"第 {i//batch_size + 1} 批数据获取失败: {e}")
                    continue
            
            self.logger.info(f"共获取到 {len(all_operational_data)} 条房源运营信息")
            
            if not all_operational_data:
                self.logger.info("未获取到任何房源运营信息，跳过数据处理")
                return {
                    'success': True,
                    'total_projects': len(project_ids),
                    'fetched_count': 0,
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            # 处理数据
            processed_data = self.data_processor.process_operational_data(all_operational_data)
            self.logger.info(f"数据处理完成，有效记录: {len(processed_data)} 条")
            
            if not processed_data:
                self.logger.warning("没有有效的处理数据")
                return {
                    'success': True,
                    'total_projects': len(project_ids),
                    'fetched_count': len(all_operational_data),
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            # 同步到数据库
            synced_count = self.data_sync_dao.sync_table_data('bjdc_lease_house', processed_data)
            
            result = {
                'success': True,
                'total_projects': len(project_ids),
                'fetched_count': len(all_operational_data),
                'processed_count': len(processed_data),
                'synced_count': synced_count
            }
            
            self.logger.info(f"房源运营信息同步完成: {result}")
            return result
            
        except Exception as e:
            self.logger.error(f"房源运营信息同步失败: {e}")
            self.logger.error(traceback.format_exc())
            return {
                'success': False,
                'error': str(e),
                'total_projects': 0,
                'fetched_count': 0,
                'processed_count': 0,
                'synced_count': 0
            }

    
    def sync_table_by_biz_sys(self, biz_sys: str, last_sync_time: Optional[str] = None, 
                                force_full: bool = False) -> Dict[str, Any]:
        """
        通用的业务系统数据同步方法
        
        Args:
            biz_sys: 业务系统名称
            last_sync_time: 上次同步时间
            force_full: 是否强制全量同步
            
        Returns:
            同步结果统计
        """
        try:
            # 获取表名
            table_name = self.data_processor.get_table_name_by_biz_sys(biz_sys)
            if not table_name:
                return {
                    'success': False,
                    'error': f'未找到业务系统 "{biz_sys}" 对应的表名',
                    'total_fetched': 0,
                    'filtered_count': 0,
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            self.logger.info(f"开始同步{biz_sys}数据到{table_name}表")
            
            # 如果没有指定上次同步时间，从数据库获取
            if not last_sync_time and not force_full:
                last_sync_time = self.data_sync_dao.get_last_sync_time(table_name)
                if last_sync_time:
                    self.logger.info(f"从数据库获取到上次同步时间: {last_sync_time}")
                else:
                    self.logger.info("数据库中无同步记录，将进行全量同步")
                    force_full = True
            
            # 获取API数据
            if force_full:
                self.logger.info("执行全量数据同步")
                api_response = self.api_client.get_full_data()
            else:
                self.logger.info(f"执行增量数据同步，基准时间: {last_sync_time}")
                api_response = self.api_client.get_incremental_data(last_sync_time)
            
            all_data = api_response.get('list', [])
            self.logger.info(f"从API获取到 {len(all_data)} 条数据")
            
            # 过滤出指定业务系统的数据
            filtered_data = []
            for item in all_data:
                if item.get('bizSys') == biz_sys:
                    filtered_data.append(item)
            
            self.logger.info(f"过滤后{biz_sys}数据: {len(filtered_data)} 条")
            
            if not filtered_data:
                self.logger.info("没有需要同步的数据")
                return {
                    'success': True,
                    'total_fetched': len(all_data),
                    'filtered_count': 0,
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            # 处理数据
            processed_data = self.data_processor.process_data_by_biz_sys(filtered_data, biz_sys)
            self.logger.info(f"数据处理完成，有效记录: {len(processed_data)} 条")
            
            if not processed_data:
                self.logger.warning("没有有效的处理数据")
                return {
                    'success': True,
                    'total_fetched': len(all_data),
                    'filtered_count': len(filtered_data),
                    'processed_count': 0,
                    'synced_count': 0
                }
            
            # 同步到数据库
            synced_count = self.data_sync_dao.sync_table_data(table_name, processed_data)
            
            result = {
                'success': True,
                'total_fetched': len(all_data),
                'filtered_count': len(filtered_data),
                'processed_count': len(processed_data),
                'synced_count': synced_count
            }
            
            self.logger.info(f"同步完成: {result}")
            return result
            
        except Exception as e:
            self.logger.error(f"同步{biz_sys}数据失败: {e}")
            self.logger.error(traceback.format_exc())
            return {
                'success': False,
                'error': str(e),
                'total_fetched': 0,
                'filtered_count': 0,
                'processed_count': 0,
                'synced_count': 0
            }
    
    def sync_all_tables(self, last_sync_time: Optional[str] = None, 
                       force_full: bool = False) -> Dict[str, Any]:
        """
        同步所有表数据（基于配置的通用方法）
        
        Args:
            last_sync_time: 上次同步时间
            force_full: 是否强制全量同步
            
        Returns:
            同步结果统计
        """
        try:
            self.logger.info("开始同步所有表数据")
            
            # 从配置中获取所有业务系统
            biz_sys_mapping = self.config.get('biz_sys_mapping', {})
            
            results = {}
            
            # 遍历所有业务系统进行同步
            for biz_sys, table_name in biz_sys_mapping.items():
                self.logger.info(f"开始同步业务系统: {biz_sys} -> {table_name}")
                result = self.sync_table_by_biz_sys(biz_sys, last_sync_time, force_full)
                results[table_name] = result
            
            # 执行房源运营信息同步
            self.logger.info("开始执行房源运营信息同步")
            operational_result = self.sync_operational_data()
            results['bjdc_lease_house'] = operational_result
            
            # 统计总体结果
            total_result = {
                'success': all(r.get('success', False) for r in results.values()),
                'tables': results,
                'summary': {
                    'total_tables': len(results),
                    'success_tables': sum(1 for r in results.values() if r.get('success', False)),
                    'total_synced': sum(r.get('synced_count', 0) for r in results.values())
                }
            }
            
            self.logger.info(f"所有表同步完成: {total_result['summary']}")
            return total_result
            
        except Exception as e:
            self.logger.error(f"同步所有表失败: {e}")
            return {
                'success': False,
                'error': str(e),
                'tables': {},
                'summary': {
                    'total_tables': 0,
                    'success_tables': 0,
                    'total_synced': 0
                }
            }
    
    def close(self):
        """
        关闭所有连接
        """
        try:
            if self.api_client:
                self.api_client.close()
            if self.operational_api_client:
                self.operational_api_client.close()
            if self.db_manager:
                self.db_manager.close()
            self.logger.info("所有连接已关闭")
        except Exception as e:
            self.logger.error(f"关闭连接失败: {e}")





def validate_table_parameter(table_name: str, config: Dict[str, Any]) -> Optional[str]:
    """
    验证表名参数并返回对应的业务系统名称
    
    Args:
        table_name: 用户输入的表名或业务系统名称
        config: 配置字典
    
    Returns:
        对应的业务系统名称，如果无效则返回None
    """
    biz_sys_mapping = config.get('biz_sys_mapping', {})
    field_mapping = config.get('field_mapping', {})
    
    # 1. 检查是否为业务系统名称
    if table_name in biz_sys_mapping:
        return table_name
    
    # 2. 检查是否为表名（从field_mapping中查找）
    if table_name in field_mapping:
        # 从biz_sys_mapping中找到对应的业务系统
        for biz_sys, table in biz_sys_mapping.items():
            if table == table_name:
                return biz_sys
    
    # 3. 向后兼容：检查是否为表名，通过biz_sys_mapping的值查找
    for biz_sys, table in biz_sys_mapping.items():
        if table == table_name:
            return biz_sys
    
    return None


def get_available_table_options(config: Dict[str, Any]) -> List[str]:
    """
    获取所有可用的表选项
    """
    biz_sys_mapping = config.get('biz_sys_mapping', {})
    field_mapping = config.get('field_mapping', {})
    
    # 收集所有可用选项：业务系统名称、表名
    options = list(biz_sys_mapping.keys()) + list(field_mapping.keys()) + list(biz_sys_mapping.values())
    
    # 去重并返回
    return list(set(options))


def parse_arguments():
    """
    解析命令行参数
    
    Returns:
        解析后的参数
    """
    parser = argparse.ArgumentParser(description='北交所数据同步程序')
    
    parser.add_argument(
        '--config', '-c',
        default='config.yaml',
        help='配置文件路径 (默认: config.yaml)'
    )
    
    parser.add_argument(
        '--table', '-t',
        default='all',
        help='要同步的表名或业务系统名称 (默认: all，支持配置文件中的所有表名和业务系统)'
    )
    
    parser.add_argument(
        '--sync-time',
        help='指定同步时间，格式: YYYY-MM-DD 或 YYYY-MM-DD HH:MM:SS'
    )
    
    parser.add_argument(
        '--full',
        action='store_true',
        help='强制全量同步'
    )
    
    parser.add_argument(
        '--test',
        action='store_true',
        help='仅测试连接，不执行同步'
    )
    
    parser.add_argument(
        '--dry-run',
        action='store_true',
        help='试运行模式，不实际写入数据库'
    )
    
    return parser.parse_args()


def main():
    """
    主函数
    """
    args = parse_arguments()
    
    # 检查配置文件是否存在
    if not os.path.exists(args.config):
        print(f"错误: 配置文件 '{args.config}' 不存在")
        sys.exit(1)
    
    sync_manager = None
    
    try:
        # 初始化同步管理器
        sync_manager = DataSyncManager(args.config)
        
        # 如果不是测试模式且不是同步所有表，先验证表名参数
        if not args.test and args.table != 'all':
            if validate_table_parameter(args.table, sync_manager.config) is None:
                available_options = get_available_table_options(sync_manager.config)
                print(f"不支持的表或业务系统: {args.table}")
                print(f"支持的选项: {', '.join(available_options)}")
                sys.exit(1)
        
        # 测试连接
        if not sync_manager.test_connections():
            print("连接测试失败，程序退出")
            sys.exit(1)
        
        if args.test:
            print("连接测试成功")
            return
        
        # 执行同步
        if args.table == 'all':
            result = sync_manager.sync_all_tables(
                last_sync_time=args.sync_time,
                force_full=args.full
            )
        else:
            # 获取对应的业务系统名称
            target_biz_sys = validate_table_parameter(args.table, sync_manager.config)
            
            if target_biz_sys:
                result = sync_manager.sync_table_by_biz_sys(
                    target_biz_sys,
                    last_sync_time=args.sync_time,
                    force_full=args.full
                )
            else:
                # 这种情况理论上不会发生，因为前面已经验证过了
                available_options = get_available_table_options(sync_manager.config)
                print(f"不支持的表或业务系统: {args.table}")
                print(f"支持的选项: {', '.join(available_options)}")
                sys.exit(1)
        
        # 输出结果
        if result.get('success'):
            print("数据同步成功")
            if 'summary' in result:
                summary = result['summary']
                print(f"同步统计: 总表数={summary['total_tables']}, "
                     f"成功表数={summary['success_tables']}, "
                     f"总同步记录数={summary['total_synced']}")
            else:
                print(f"同步记录数: {result.get('synced_count', 0)}")
        else:
            print(f"数据同步失败: {result.get('error', '未知错误')}")
            sys.exit(1)
    
    except KeyboardInterrupt:
        print("\n用户中断程序")
        sys.exit(1)
    except Exception as e:
        print(f"程序执行失败: {e}")
        traceback.print_exc()
        sys.exit(1)
    finally:
        if sync_manager:
            sync_manager.close()


if __name__ == '__main__':
    main()